iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0

以下是流程簡單的描述

  1. 初始:已建立/等待啟動
  2. 呼叫 Start 或被排程 → 進入等待執行
  3. 執行緒池呼叫 ExecuteEntry → 執行中(委派已觸發)
  4. 使用者委派執行結果:成功/拋出例外/拋出 OperationCanceledException
  5. 標記使用者委派已執行
  6. 若有子任務則等待全部完成 → 子任務完成
  7. 第二階段收斂:設定狀態 RanToCompletion/Faulted/Canceled
  8. 第三階段:清理資源+通知父任務+排程接續
  9. 後續觸發:await/ContinueWith/WhenAll 等

IL 對應 await

IL_000a: callvirt  instance class [System.Net.Http]System.Threading.Tasks.Task`1<string>
                         [System.Net.Http]System.Net.Http.HttpClient::GetStringAsync(string)
IL_000f: callvirt  instance valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<string>
                         class [System.Runtime]System.Threading.Tasks.Task`1<string>::GetAwaiter()
IL_0014: stloc.0                      // 暫存 awaiter
IL_0015: ldloca.s 0
IL_0017: call instance bool [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<string>::get_IsCompleted()
IL_001c: brtrue.s   IL_0039
// 未完成路徑(掛起)
IL_001e: ldarg.0
IL_001f: ldc.i4.0
IL_0020: stfld int32 <>1__state
IL_0025: ldarg.0
IL_0026: ldloc.0
IL_0027: stfld valuetype TaskAwaiter`1<string> <>u__1
IL_002c: ldarg.0
IL_002d: ldflda valuetype AsyncTaskMethodBuilder`1<int32> <>t__builder
IL_0032: ldloca.s 0
IL_0034: ldarg.0
IL_0035: call instance void AsyncTaskMethodBuilder`1<int32>::AwaitUnsafeOnCompleted(
                     !!0&, !!1&)
IL_003a: ret
// 已完成快速路徑
IL_0039: ldloca.s 0
IL_003b: call instance string TaskAwaiter`1<string>::GetResult()

Awaiter 基本契約

可被 await 的型別需提供:

  1. GetAwaiter()
  2. Awaiter 需具備:bool IsCompleted、void OnCompleted(Action) 或 UnsafeOnCompleted(Action)、TResult GetResult()

TaskAwaiter / ValueTaskAwaiter 為內建。AwaitUnsafeOnCompleted 優先使用 UnsafeOnCompleted 以避免不必要的 ExecutionContext 複製。

同步快速路徑

IsCompleted 為 true 時直接續執行,不掛起也不排程。大量同步命中(快取、已完成 I/O)是使用 ValueTask 降低配置的前提。

例外與取消

  • 例外於 MoveNext 中被捕捉並呼叫 SetException,狀態為 Faulted
  • OperationCanceledException(含符合 Token)最終標記為 Canceled
  • await 的 GetResult 重新拋出第一層原始例外(非 Aggregate 包)

ConfigureAwait(false)

影響續接排程:

  • 預設 true:捕捉 SynchronizationContext(如 UI)
  • false:略過 SynchronizationContext,但仍流動 ExecutionContext
  • IL 會使用 ConfiguredTaskAwaitable.ConfiguredTaskAwaiter,狀態機模式不變

Q. ValueTask 差異
AsyncValueTaskMethodBuilder:

  • 同步完成:直接包裝結果,不配置 Task
  • 真正非同步:可能配置 Task 或使用 IValueTaskSource
  • 同一個 ValueTask 不應多次 await(除非轉為 AsTask)

Q. 為何可能出現盒裝狀態機
ref struct 無法實作介面,當需以 IAsyncStateMachine 形式傳遞(如偵錯掛勾)可能產生一次性 boxing,編譯器已盡量避免。


上一篇
async/await 降糖展開(狀態機 IL 分析)
下一篇
常見效能問題
系列文
新 .NET & Azure & IoT & AI 開源技術實戰手冊 (含深入官方程式碼講解) 26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言